package com.auxiliary;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class BasicCalculator {
	
	private double[] HendersonFilters_9 = {
			-0.041, -0.010, 0.119, 0.267, 0.330,
			0.267, 0.119, -0.010, -0.041
			};
	private double[] HendersonFilters_13 = {
			-0.019, -0.028, 0.0, 0.066, 0.147,
			0.214, 0.240, 0.214, 0.147, 0.066,
			0.0, -0.028, -0.019
			};
	private double[] HendersonFilters_23 = {
			-0.004, -0.011, -0.016, -0.015, -0.005,
			0.013, 0.039, 0.068, 0.097, 0.122,
			0.138, 0.148, 0.138, 0.122, 0.097,
			0.068, 0.039, 0.013, -0.005, -0.015,
			-0.016, -0.011, -0.004
			};
	
	//求最大值
	public double getMax(List<Double> list) {
		double max = Double.MIN_VALUE;
		
		for(Double v: list)
			max = max < v? v: max;
		
		return max;
	}
	
	//求最小值
	public double getMin(List<Double> list) {
		double min = Double.MAX_VALUE;
		
		for(Double v: list)
			min = min > v? v: min;
		
		return min;
	}
	
	//计算和
	public double calcSum(List<Double> list) {
		double sum = 0;
		
		for(Double v: list)
			sum += v;
		
		return sum;
	}
	
	//计算均值
	public double calcAvg(List<Double> list) {
		return calcSum(list) / list.size();
	}
	
	//计算绝对均值
	public double calcAbsAvg(List<Double> list) {
		double sum = 0;
		
		for(Double v: list)
			sum += Math.abs(v);
		
		return sum / list.size();
	}
	
	//计算标准差
	public double calcStdev(List<Double> list) {
		double sumSqr = 0;
		double avg = calcAvg(list);
		
		for(Double v: list)
			sumSqr += (v - avg) * (v - avg);
		
		return Math.sqrt(sumSqr / (list.size() - 1));
	}
	
	//计算中位数
	public double calcMedian(List<Double> list) {
		if(list.size() == 0)
			return -99999999;
		if(list.size() == 1)
			return list.get(0);
		
		List<Double> temp = new ArrayList<Double>(list);
		Collections.sort(temp);
		
		int i = list.size() / 2;
		if(list.size() % 2 != 0)
			return list.get(i / 2);
		else
			return (temp.get(i) + temp.get(i - 1)) / 2.0;
	}
	
	//计算偏度
	public double calcSkewness(List<Double> list) {
		if(list.size() == 0)
			return -9999999;
		
		double sd = calcStdev(list);
		double avg = calcAvg(list);
		
		double sum = 0;
		for(Double v: list)
			sum += (v - avg) * (v - avg) * (v - avg);
		return (sum / (list.size() - 1)) / (sd * sd * sd);
	}
	
	//计算峰度
	public double calcKurtosis(List<Double> list) {
		if(list.size() == 0)
			return -9999999;
		
		double sd = calcStdev(list);
		double avg = calcAvg(list);
		
		double sum = 0;
		for(Double v: list)
			sum += (v - avg) * (v - avg) * (v - avg) * (v - avg);
		return (sum / (list.size() - 1)) / (sd * sd * sd * sd) - 3;
	}
	
	//进行spencer移动平均
	public List<Double> DoSpencer(List<Double> list)
    {
        int size = list.size();
        
        List<Double> movingList = new ArrayList<Double>();
        List<Double> extendList = new ArrayList<Double>(list);

        double head = (list.get(0) + list.get(1) + list.get(2)+ list.get(3)) / 4;
        double tail = (list.get(size - 1) + list.get(size - 2) + list.get(size - 3) + list.get(size - 4)) / 4;
        
        for (int i = 0; i < 7; i++) //将序列的长度加15
        {
        	extendList.add(i, head);
        	extendList.add(tail);
        }

        for (int i = 0; i < size; i++)
        {
        	double temp = (-3 * extendList.get(i) - 6 * extendList.get(i + 1) - 5 * extendList.get(i + 2) + 3 * extendList.get(i + 3) + 21 * extendList.get(i + 4) + 46 * extendList.get(i + 5) + 67 * extendList.get(i + 6) + 74 * extendList.get(i + 7) + 67 * extendList.get(i + 8) + 46 * extendList.get(i + 9) + 21 * extendList.get(i + 10) + 3 * extendList.get(i + 11) - 5 * extendList.get(i + 12) - 6 * extendList.get(i + 13) - 3 * extendList.get(i + 14)) / 320;
            movingList.add(temp);
        }
        return movingList;
    }
	
	//对时间序列进行移动平均
	public List<Double> movingAvg(int order, List<Double> list) {
		if(order <= 0)
			return list;
		
		int extendCount = 0;
		if(order % 2 == 0)
			extendCount = order / 2;
		else
			extendCount = (order - 1) / 2;

		List<Double> movingList = new ArrayList<Double>();
		List<Double> extendList = new ArrayList<Double>(list);
		
		double headSum = 0;
		double tailSum = 0;
		for(int i = 0; i < extendCount; i++) {
			headSum += list.get(i);
			tailSum += list.get(list.size() - extendCount + i);
		}
		
		for(int i = 0; i < extendCount; i++) {
			extendList.add(i, headSum / extendCount);
			extendList.add(tailSum / extendCount);
		}
		
		if(order % 2 == 0) {
			double sum = 0;
			for(int i = 0; i < order; i++) {
				if(i == 0 || i == order)
					sum += extendList.get(i) / 2;
				else
					sum += extendList.get(i);
			}
			
			movingList.add(sum / order);
			
			for(int i = 1; i < list.size(); i++) {
				sum += extendList.get(order + i - 1) - (extendList.get(i) + extendList.get(i - 1)) / 2;
				movingList.add(sum / order);
			}
		}
		else {
			double sum = 0;
			for(int i = 0; i < order; i++)
				sum += extendList.get(i);
			movingList.add(sum / order);
			
			for(int i = 1; i < list.size(); i++) {
				sum += extendList.get(order + i - 1) - extendList.get(i - 1);
				movingList.add(sum / order);
			}
		}
		
		return movingList;
	}
	
	//进行M*N移动平均
	public List<Double> M_Mul_NMoving(List<Double> list, int m, int n) {
		if(n <= 0)
			return list;
		
		int extendCount = (n + 1) / 2;
		
		List<Double> movingList = new ArrayList<Double>();
		
		List<Double> extendList = extendList(list, extendCount);
		
		if(n % 2 == 0) {
			double sum = 0;
			for(int i = 0; i <= n; i++) {
				if(i == 0 || i == n)
					sum += extendList.get(i) * m / 2;
				else
					sum += extendList.get(i) * m;
			}
			
			movingList.add(sum / m / n);
			
			for(int i = 1; i < list.size(); i++) {
				sum += (extendList.get(n + i) + extendList.get(n + i - 1) - extendList.get(i) - extendList.get(i - 1)) * m / 2;
				movingList.add(sum / m / n);
			}
		}
		else {
			for(int i = 0; i < list.size(); i++) {
				int mul = 1;
				double sum = 0;
				int j = 0;
				
				for(j = i; j < i + extendCount; j++) {
					sum += mul++ * extendList.get(j);
					mul = mul > m? m: mul;
				}
				
				sum += extendList.get(j) * mul;
				mul = 1;
				
				for(j = i + 2 * extendCount; j > i + extendCount; j--) {
					sum += mul++ * extendList.get(j);
					mul = mul > m? m: mul;
				}
				
				movingList.add(sum / m / n);
			}
		}
		
		return movingList;
	}
	
	//进行Henderson移动平均
	public List<Double> hendersonList(List<Double> list, int n) {
		double[] filters;
		if(n == 9)
			filters = this.HendersonFilters_9;
		else if(n == 23)
			filters = this.HendersonFilters_23;
		else
			filters = this.HendersonFilters_13;
		
		int extendCount = (filters.length - 1) / 2;
		
		List<Double> movingList = new ArrayList<Double>();
		
		List<Double> extendList = extendList(list, extendCount);
		
		for(int i = 0; i < list.size(); i++) {
			
			double temp = 0;
			
			for(int j = i; j < i + filters.length; j++)
				temp += extendList.get(j) * filters[j - i];
			
			movingList.add(temp);
		}
		
		return movingList;
	}
	
	/// <summary>
    /// 加权移动平均
    /// 加权移动平均阶数应为大于0的奇数。如果输入阶数小于等于0，返回输入序列。如果阶数为偶数，返回移动平均结果。
    /// 加权移动平均权重序列长度应等于加权移动平均阶数。如果不等，则返回输入序列。
    /// </summary>
    /// <param name="_order">加权移动平均阶数</param>
    /// <param name="dataArrayList">输入序列</param>
    /// <param name="weightArrayList">加权移动平均权重序列</param>
    /// <returns></returns>
    public List<Double> MAverWithWeight(int order, List<Double> dataArrayList, List<Double> weightArrayList)
    {
        if (order <= 0) return dataArrayList;
        if (order != weightArrayList.size()) return dataArrayList;
        
        Double[] array = (Double[]) dataArrayList.toArray();           
        Double a=(order-1.0)/2.0;
        int halfOrder =(int) Math.floor(a);
        boolean isEvenOrder = false; //是否是偶数阶
        if (order / 2 - halfOrder > 0) { halfOrder += 1; isEvenOrder = true; }
        
        int arrayLength=array.length;
        Double[] extendArray = new Double[arrayLength + order];
        Double[] movingArray = new Double[arrayLength];
        extendArray[0] = 0.0;
        for (int i = 0; i < halfOrder; i++) //增加序列长度
        {
            for (int j = 0; j < halfOrder; j++)
            {
            	extendArray[i] += array[j];
                extendArray[arrayLength + i+halfOrder] += array[arrayLength -halfOrder+j]; 
            }
            extendArray[i] = extendArray[i] / halfOrder;
            extendArray[arrayLength + i+ halfOrder] = extendArray[arrayLength + halfOrder + i] / halfOrder;
        }
        for (int i = 0; i < arrayLength; i++)
        {
            extendArray[halfOrder + i] = array[i];
        }

        if (isEvenOrder) //是偶数阶
        {
            for (int i = 0; i < arrayLength; i++)
            {
                for (int j = 0; j < order; j++)
                    if (j == 0 || j == order)
                        movingArray[i] += extendArray[i + j] / 2;
                    else
                        movingArray[i] += extendArray[i + j];
                movingArray[i] = movingArray[i] / order;
            }
        }
        else //是奇数阶
        {
            for (int i = 0; i < arrayLength; i++)
            {
                for (int j = 0; j < order; j++)
                    movingArray[i] += extendArray[i+j] * weightArrayList.get(j);
                
            }
        }
        return new ArrayList<Double>(Arrays.asList(movingArray));
    }
    
	//序列延长
	public List<Double> extendList(List<Double> list, int extendCount) {
		
		List<Double> extendList = new ArrayList<Double>(list);
		
		double headSum = 0;
		double tailSum = 0;
		for(int i = 0; i < extendCount; i++) {
			headSum += list.get(i);
			tailSum += list.get(list.size() - extendCount + i);
		}
		
		for(int i = 0; i < extendCount; i++) {
			extendList.add(i, headSum / extendCount);
			extendList.add(tailSum / extendCount);
		}
		
		return extendList;
	}
	
	//序列间加减乘除
	public List<Double> listPSME(List<Double> list1, List<Double> list2, int type) {
		List<Double> res = new ArrayList<Double>();
		if(list1.size() != list2.size())
			return null;
		
		for(int i = 0; i < list1.size(); i++) {
			if(type == 1)
				res.add(list1.get(i) + list2.get(i));
			else if(type == 2)
				res.add(list1.get(i) - list2.get(i));
			else if(type == 3)
				res.add(list1.get(i) * list2.get(i));
			else
				res.add(list1.get(i) / list2.get(i));
		}
		
		return res;
	}
	
	public int[][] findPV(List<Double> list){
		int size = list.size();
		int count = -1;
		int table[][] = new int[size][2];
		
		for(int i = 1; i < size - 1; i++) {
			if((list.get(i) - list.get(i - 1)) * (list.get(i) - list.get(i + 1)) >= 0) {
				count++;
				table[count][0] = i;
				if(list.get(i) >= list.get(i - 1) & list.get(i) >= list.get(i + 1))
					table[count][1] = 1;
				else
					table[count][1] = 0;
			}
		}
		
		System.out.println("asd");
		
		int table2[][] = new int[count + 1][2];
		for(int i = 0; i <= count; i++) {
			table2[i][0] = table[i][0];
			table2[i][1] = table[i][1];
		}
		
		return table2;
	}
	
	
	//筛选谷峰
	public int[][] findConstriantPV(int[][] PVSeries, int halfPeriod, int onePeriod)
    {
        if (halfPeriod < 0 || onePeriod < 0 || halfPeriod > onePeriod) return null;
        int TableLength = PVSeries.length;
        int[][] Table2 = new int[TableLength][2];
        int[][] Table3 = new int[TableLength][2];

        int a, b, c, d;
        a = c = 0;
        b = d = -1;

        while (a < TableLength - 1)
        {
            if (PVSeries[a + 1][0] - PVSeries[a][0] >= halfPeriod)
            {
                b = b + 1;
                Table2[b][0] = PVSeries[a][0];
                Table2[b][1] = PVSeries[a][1];
                a = a + 1;
            }
            else
            {
                a = a + 2;
            }
        }
        if (a == TableLength - 1)
        {
            b = b + 1;
            Table2[b][0] = PVSeries[a][0];
            Table2[b][1] = PVSeries[a][1];
        }

        while (c < b - 1)
        {
            if (Table2[c + 2][0] - Table2[c][0] >= onePeriod)
            {
                d = d + 1;
                Table3[d][0] = Table2[c][0];
                Table3[d][1] = Table2[c][1];
                c = c + 1;
            }
            else
            {
                c = c + 2;
            }
        }
        if (c == b - 1)
        {
            d = d + 1;
            Table3[d][0] = Table2[c][0];
            Table3[d][1] = Table2[c][1];
            d = d + 1;
            c = c + 1;
            Table3[d][0] = Table2[c][0];
            Table3[d][1] = Table2[c][1];
        }

        int[][] Table4 = new int[d + 1][2];
        for (int i = 0; i <= d; i++)
        {
            Table4[i][0] = Table3[i][0];
            Table4[i][1] = Table3[i][1];
        }

        return Table4;
    }
	
	public int[][] adjustPV(int[][] PVSeries, int MCD, List<Double> list)
	{

        int r;
		if(MCD <= 4)
			r = 4;
		else
			r = MCD;
		
		int size = list.size();
		int count = PVSeries.length;
		
		int Table2[][] = new int[count][2];

		for(int i = 0; i < count; i++)
		{
			int InfBound,SupBound;
			InfBound = PVSeries[i][0] < r? 0: (PVSeries[i][0] - r);
			SupBound = ((PVSeries[i][0] + r) > (size - 1))? (size - 1): (PVSeries[i][0] + r);
			
			int mpos = PVSeries[i][0];
			double mnum = list.get(PVSeries[i][0]);

			if(PVSeries[i][1] == 1)
			{
				for(int j = InfBound; j <= SupBound; j++)
				{
					if(list.get(j) > mnum)
					{
						mpos = j;
						mnum = list.get(j);
					}
				}
			}
			else
			{
				for(int j = InfBound; j <= SupBound; j++)
				{
					if(list.get(j) < mnum)
					{
						mpos = j;
						mnum = list.get(j);
					}	
				}
			}

			Table2[i][0] = mpos;
			Table2[i][1] = PVSeries[i][1];
		}
		return Table2;
	}
	
	//消除特异值
	public List<Double> removeOutlier(List<Double> list)
    {

        List<Double> newList = new ArrayList<Double>();
        
        int A = 2;///the outlier parameter
        
        double mean = calcAvg(list);
        double std = calcStdev(list);
        
        List<Double> spencerList = DoSpencer(list);
        
        for (int i = 0; i < list.size(); i++)
        {
            if (list.get(i) < mean - A * std || list.get(i) > mean + A * std)
            	newList.add(spencerList.get(i));
            else
            	newList.add(list.get(i));
        }

        return newList;
    }
	
	//对月分进行加法操作
	public String addMonth(String start, int i)
    {
		String[] temp = start.split("-");
		int year = Integer.valueOf(temp[0]);
		int month = Integer.valueOf(temp[1]);
		
		year += (month + i) / 12;
		
		if(month + i > 12)
			month = (month + i) % 12 == 0? 12: (month + i) % 12;
		else
			month += i;
		
        return year + "-" + String.format("%02d", month);     
    }
	
	public int getDatesDiff(String startDate, String endDate)
    {
		
		String[] start = startDate.split("-");
		int startYear = Integer.valueOf(start[0]);
		int startMonth = Integer.valueOf(start[1]);
		
		String[] end = endDate.split("-");
		int endYear = Integer.valueOf(end[0]);
		int endMonth = Integer.valueOf(end[1]);	
		

        return (endYear - startYear) * 12 + (endMonth - startMonth);
    }
	
	public int getDataCount(String startDate, String endDate)
    {
		return Math.abs(this.getDatesDiff(startDate, endDate)) + 1;
    }
}
